package com.study.store.s3;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URL;
import java.util.*;

import static com.study.store.s3.S3Service.conn;

/**
 * @author tc
 * @date 2019/1/2
 */
public class S3Help {

    private static final Logger logger = LoggerFactory.getLogger(S3Help.class);

    public static AmazonS3 createClient(String accessKey, String secretKey, String endpointUrl) {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
            endpointUrl, Regions.CN_NORTH_1.getName());
        return AmazonS3ClientBuilder.standard().withEndpointConfiguration(endpointConfiguration)
            .withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build();
    }

    /**
     * If versioning is not enabled, this operation will overwrite an existing object<br> with the same key; Amazon S3
     * will store the last write request.<br> Amazon S3 does not provide object locking.<br> If Amazon S3 receives
     * multiple write requests for the same object nearly<br> simultaneously, all of the objects might be stored.
     * However, a single<br> object will be stored with the final write request.<br>
     *
     * @param conn
     * @param bucketName
     * @param key
     */
    public static PutObjectResult putObject(AmazonS3 conn, String bucketName, String key, InputStream inputStream) {
        return putObject(conn, bucketName, key, inputStream, new ObjectMetadata());
    }

    public static PutObjectResult putObject(AmazonS3 conn, String bucketName, String key, InputStream inputStream,
                                            ObjectMetadata metadata) {
        return conn.putObject(new PutObjectRequest(bucketName, key, inputStream, metadata));
    }

    public static PutObjectResult putObject(AmazonS3 conn, String bucketName, String key, File file) {
        return conn.putObject(new PutObjectRequest(bucketName, key, file));
    }

    /**
     * 目前测试未生效 因为bucket private or public 已经设置
     *
     * @param conn
     * @param bucketName
     * @param key
     * @param inputStream
     * @param accessControlList
     * @return
     */
    public static PutObjectResult putObject(AmazonS3 conn, String bucketName, String key, InputStream inputStream,
                                            CannedAccessControlList accessControlList) {
        return conn.putObject(
            new PutObjectRequest(bucketName, key, inputStream, new ObjectMetadata()).withCannedAcl(accessControlList));
    }

    /**
     * 目前测试未生效 因为bucket private or public 已经设置
     *
     * @param conn
     * @param bucketName
     * @param key
     * @param file
     * @param accessControlList
     * @return
     */
    public static PutObjectResult putObject(AmazonS3 conn, String bucketName, String key, File file,
                                            CannedAccessControlList accessControlList) {
        return conn.putObject(new PutObjectRequest(bucketName, key, file).withCannedAcl(accessControlList));
    }

    public static ObjectMetadata getObject(AmazonS3 conn, String bucketName, String key, File destinationFile) {
        if (bucketName.isEmpty() || key.isEmpty()) {
            return null;
        }

        return conn.getObject(new GetObjectRequest(bucketName, key), destinationFile);
    }

    public static S3Object getObject(AmazonS3 conn, String bucketName, String key) {
        if (bucketName.isEmpty() || key.isEmpty()) {
            return null;
        }

        return conn.getObject(new GetObjectRequest(bucketName, key));
    }

    public static void deleteObject(AmazonS3 conn, String bucketName, String key) {
        if (bucketName.isEmpty() || key.isEmpty()) {
            throw new RuntimeException("bucketName and key can not be empty");
        }

        conn.deleteObject(bucketName, key);
    }

    public static String putObjectGetUrl(AmazonS3 conn, String bucketName, String key, File file,
                                         CannedAccessControlList accessControlList) {
        PutObjectResult putObjectResult = putObject(conn, bucketName, key, file, accessControlList);
        if (logger.isDebugEnabled()) {
            logger.debug(putObjectResult.getETag());
        }
        GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName, key);
        URL url = conn.generatePresignedUrl(urlRequest);
        return url.toString();
    }

    public static String readString(AmazonS3 conn, String bucketName, String key) {
        int i;
        StringBuilder sb = new StringBuilder();
        S3Object object = conn.getObject(bucketName, key);
        try (S3ObjectInputStream objectContent = object.getObjectContent();
             FilterInputStream fis = new BufferedInputStream(objectContent)) {
            while ((i = fis.read()) != -1) {
                sb.append((char)i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return sb.toString();
    }

    public static InputStream readStream(AmazonS3 conn, String bucketName, String key) {
        S3Object object = conn.getObject(bucketName, key);
        return object.getObjectContent();
    }

    public static boolean isExist(AmazonS3 conn, String bucketName, String key) {
        try {
            S3Object object = conn.getObject(bucketName, key);
        } catch (AmazonS3Exception e) {
            e.printStackTrace();
            if (e.getErrorCode().equals("NoSuchKey") && e.getStatusCode() == 404) {
                return false;
            }
        }

        return true;
    }

    public static ObjectListing listObject(AmazonS3 conn, String bucketName) {
        ObjectListing objects = conn.listObjects(bucketName);
        do {
            for (S3ObjectSummary objectSummary : objects.getObjectSummaries()) {
                System.out.println(objectSummary.getKey() + "\t" +
                    objectSummary.getSize() + "\t" +
                    StringUtils.fromDate(objectSummary.getLastModified()) + "\t");
            }
            objects = conn.listNextBatchOfObjects(objects);
        } while (objects.isTruncated());

        return objects;
    }

    /**
     * 获取下载的URL default one hour
     *
     * @param conn
     * @param bucketName
     * @param key
     * @return
     */
    public static String getUrl(AmazonS3 conn, String bucketName, String key) {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key);
        return conn.generatePresignedUrl(request).toString();
    }

    public static String getUrl(AmazonS3 conn, String bucketName, String key, Date date) {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key).withExpiration(date);
        return conn.generatePresignedUrl(request).toString();
    }

    public static String getUrl(AmazonS3 conn, String bucketName, String key, long time) {
        Date date = new Date();
        date.setTime(time);
        return getUrl(conn, bucketName, key, date);
    }

    /**
     * 获取该连接下所有的容器信息
     *
     * @return
     */
    public static List<Bucket> getBuckets(AmazonS3 conn) {
        List<Bucket> buckets = conn.listBuckets();
        return buckets;
    }

    public Bucket getBuketsByname(AmazonS3 conn, String bucketName) {
        Bucket resultBucket = null;

        if (bucketName != null) {
            List<Bucket> buckets = conn.listBuckets();
            if (buckets != null) {
                for (Bucket bucket : buckets) {
                    if (bucketName.equals(bucket.getName())) {
                        resultBucket = bucket;
                        break;
                    }
                }
            }
        }

        return resultBucket;
    }

    /**
     * 新建容器名称
     *
     * @param conn
     * @param bucketName
     * @return
     */
    public Bucket creatBucket(AmazonS3 conn, String bucketName) {
        Bucket bucket = null;
        if (!bucketName.isEmpty()) {
            bucket = conn.createBucket(bucketName);
        }

        return bucket;
    }

    /**
     * 获取该容器下面的所有信息(文件目录集合和文件信息集合)
     *
     * @param bucketName
     * @return
     */
    public ObjectListing getBacketObjects(AmazonS3 conn, String bucketName) {
        ObjectListing objects = null;
        if (!bucketName.isEmpty()) {
            objects = conn.listObjects(bucketName);
        }

        return objects;
    }

    /**
     * 获取某个文件(前缀路径)下的所有信息
     *
     * @param bucketName
     * @param prefix
     * @param isDelimiter
     * @return
     */
    public ObjectListing getBacketObjects(AmazonS3 conn, String bucketName, String prefix, Boolean isDelimiter) {
        if (bucketName == null || bucketName.isEmpty()) {
            return null;
        }

        ListObjectsRequest objectsRequest = new ListObjectsRequest().withBucketName(bucketName);

        if (prefix != null && !prefix.isEmpty()) {
            objectsRequest = objectsRequest.withPrefix(prefix);
        }

        if (isDelimiter) {
            objectsRequest = objectsRequest.withDelimiter("/");
        }

        ObjectListing objects = conn.listObjects(objectsRequest);

        return objects;
    }

    /**
     * 获取当前容器下面的目录集合
     *
     * @param objects
     * @return
     */
    public List<Map<String, String>> getDirectList(ObjectListing objects) {
        List<Map<String, String>> diectList = new ArrayList<>();
        String prefix = objects.getPrefix();
        do {
            List<String> commomprefix = objects.getCommonPrefixes();

            for (String comp : commomprefix) {
                Map<String, String> map = new HashMap<>();
                String dirName = comp.substring(prefix == null ? 0 : prefix.length(), comp.length() - 1);
                map.put("name", dirName);
                map.put("type", "文件夹");
                diectList.add(map);
            }

            objects = conn.listNextBatchOfObjects(objects);
        } while (objects.isTruncated());

        return diectList;
    }

    //创建文件目录
    public static Boolean creatpath(String bucketName, String StorageObjectVoPath, String folderName) {
        if (bucketName == null || folderName == null) {
            return false;
        }
        if (StorageObjectVoPath == null || StorageObjectVoPath.isEmpty() || "null".equals(StorageObjectVoPath)) {
            StorageObjectVoPath = "";
        }

        String key = StorageObjectVoPath + folderName + "/";
        ByteArrayInputStream local = new ByteArrayInputStream("".getBytes());
        PutObjectResult result = conn.putObject(bucketName, key, local, new ObjectMetadata());
        return true;

    }

    public static Boolean deleteBucket(String bucketName) {
        if (bucketName.isEmpty()) {
            return false;
        }

        return conn.doesBucketExistV2(bucketName);
    }

    public static boolean moveObject(AmazonS3 conn, String sourceBucketName, String sourceKey,
                                     String destinationBucketName, String destinationKey) {
        CopyObjectResult result = conn.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
        deleteObject(conn, sourceBucketName, sourceKey);
        if (result != null) {
            return true;
        }

        return false;
    }

}
